<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI语音对话助手</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }

        .container {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 20px;
            padding: 40px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
            text-align: center;
            max-width: 400px;
            width: 100%;
            backdrop-filter: blur(10px);
        }

        .title {
            color: #333;
            margin-bottom: 20px;
            font-size: 24px;
            font-weight: 600;
        }


        .status-text {
            color: #666;
            margin-bottom: 30px;
            font-size: 16px;
            min-height: 20px;
        }

        .voice-button {
            width: 120px;
            height: 120px;
            border-radius: 50%;
            border: none;
            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            color: white;
            font-size: 48px;
            cursor: pointer;
            transition: all 0.3s ease;
            margin: 0 auto 30px;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 10px 30px rgba(79, 172, 254, 0.3);
        }

        .voice-button:hover {
            transform: scale(1.05);
            box-shadow: 0 15px 40px rgba(79, 172, 254, 0.4);
        }

        .voice-button:active {
            transform: scale(0.95);
        }

        .voice-button.recording {
            background: linear-gradient(135deg, #ff6b6b 0%, #ffa500 100%);
            animation: pulse 1.5s infinite;
        }

        .voice-button.processing {
            background: linear-gradient(135deg, #ffd93d 0%, #ff6b6b 100%);
            animation: pulse 1s infinite;
        }

        .voice-button.speaking {
            background: linear-gradient(135deg, #6bcf7f 0%, #4facfe 100%);
            animation: pulse 0.8s infinite;
        }

        .voice-button.playing {
            background: linear-gradient(135deg, #4facfe 0%, #6bcf7f 100%);
            animation: pulse 0.6s infinite;
        }

        .play-button {
            width: 120px;
            height: 50px;
            border-radius: 25px;
            border: none;
            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            color: white;
            font-size: 16px;
            cursor: pointer;
            transition: all 0.3s ease;
            margin: 0 auto 30px;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 10px 30px rgba(79, 172, 254, 0.3);
        }

        .play-button:hover {
            transform: scale(1.05);
            box-shadow: 0 15px 40px rgba(79, 172, 254, 0.4);
        }

        .play-button:active {
            transform: scale(0.95);
        }

        .play-button.playing {
            background: linear-gradient(135deg, #6bcf7f 0%, #4facfe 100%);
            animation: pulse 0.6s infinite;
        }

        @keyframes pulse {
            0% {
                transform: scale(1);
            }
            50% {
                transform: scale(1.1);
            }
            100% {
                transform: scale(1);
            }
        }

        .controls {
            display: flex;
            gap: 15px;
            justify-content: center;
            flex-wrap: wrap;
        }

        .control-btn {
            padding: 12px 24px;
            border: none;
            border-radius: 25px;
            background: #f8f9fa;
            color: #333;
            cursor: pointer;
            font-size: 14px;
            font-weight: 500;
            transition: all 0.3s ease;
            border: 2px solid transparent;
        }

        .control-btn:hover {
            background: #e9ecef;
            transform: translateY(-2px);
        }

        .control-btn.exit {
            background: #ff6b6b;
            color: white;
        }

        .control-btn.exit:hover {
            background: #ff5252;
        }

        .visualizer {
            display: none;
            margin: 20px 0;
        }

        .visualizer.active {
            display: block;
        }

        .wave {
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 3px;
        }

        .wave-bar {
            width: 4px;
            background: #4facfe;
            border-radius: 2px;
            animation: wave 1.2s ease-in-out infinite;
        }

        .wave-bar:nth-child(2) {
            animation-delay: -1.1s;
        }

        .wave-bar:nth-child(3) {
            animation-delay: -1.0s;
        }

        .wave-bar:nth-child(4) {
            animation-delay: -0.9s;
        }

        .wave-bar:nth-child(5) {
            animation-delay: -0.8s;
        }

        @keyframes wave {
            0%, 40%, 100% {
                transform: scaleY(0.4);
            }
            20% {
                transform: scaleY(1);
            }
        }

        .volume-indicator {
            width: 100%;
            height: 4px;
            background: #e9ecef;
            border-radius: 2px;
            margin: 20px 0;
            overflow: hidden;
        }

        .volume-bar {
            height: 100%;
            background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%);
            width: 0%;
            transition: width 0.1s ease;
        }

        .hidden {
            display: none;
        }

        /* 响应式设计 */
        @media (max-width: 480px) {
            .container {
                padding: 30px 20px;
                margin: 10px;
            }

            .title {
                font-size: 20px;
                margin-bottom: 20px;
            }

            .voice-button {
                width: 100px;
                height: 100px;
                font-size: 40px;
            }

            .controls {
                flex-direction: column;
                align-items: center;
            }

            .control-btn {
                width: 100%;
                max-width: 200px;
            }
        }
    </style>
</head>
<body>
<div class="container">
    <h1 class="title">AI语音对话助手</h1>

    <div class="status-text" id="statusText">点击开始对话</div>

    <button class="voice-button" id="voiceButton" onclick="toggleRecording()">
        🎤
    </button>

    <button class="play-button hidden" id="playButton" onclick="playRecordedAudio()">
        ▶️ 播放录音
    </button>

    <div class="volume-indicator" id="volumeIndicator">
        <div class="volume-bar" id="volumeBar"></div>
    </div>

    <div class="visualizer" id="visualizer">
        <div class="wave">
            <div class="wave-bar" style="height: 20px;"></div>
            <div class="wave-bar" style="height: 35px;"></div>
            <div class="wave-bar" style="height: 25px;"></div>
            <div class="wave-bar" style="height: 40px;"></div>
            <div class="wave-bar" style="height: 30px;"></div>
        </div>
    </div>

    <div class="controls">
        <button class="control-btn" onclick="toggleMute()" id="muteBtn">静音</button>
        <button class="control-btn" onclick="testAIServices()" id="testBtn">测试AI</button>
        <button class="control-btn exit" onclick="exitConversation()">退出对话</button>
    </div>
</div>

<script>
    // 录音状态管理
    let isRecording = false;
    let mediaRecorder = null;
    let audioChunks = [];
    let audioContext = null;
    let audioBuffer = null;
    let isPlaying = false;
    let recordedAudioBlob = null; // 保存录制的音频

    // DOM元素
    const voiceButton = document.getElementById('voiceButton');
    const playButton = document.getElementById('playButton');
    const statusText = document.getElementById('statusText');
    const volumeBar = document.getElementById('volumeBar');
    const visualizer = document.getElementById('visualizer');

    // 初始化
    document.addEventListener('DOMContentLoaded', function () {
        initializeAudio();
    });



    // 更新状态文本
    function updateStatus(message, status) {
        statusText.textContent = message;

        // 更新按钮状态
        voiceButton.className = 'voice-button';
        if (status === 'processing') {
            voiceButton.classList.add('processing');
        } else if (status === 'synthesizing') {
            voiceButton.classList.add('speaking');
        } else if (status === 'completed') {
            voiceButton.classList.remove('processing', 'speaking');
        }
    }

    // 初始化音频
    function initializeAudio() {
        try {
            audioContext = new (window.AudioContext || window.webkitAudioContext)();
            console.log('音频上下文初始化成功');
        } catch (error) {
            console.error('音频上下文初始化失败:', error);
        }
    }

    // 播放音频
    function playAudio(audioBase64, sampleRate = 16000) {
        if (!audioContext || isPlaying) return;

        try {
            // 解码base64音频数据
            const audioData = atob(audioBase64);
            const audioBuffer = new Uint8Array(audioData.length);
            for (let i = 0; i < audioData.length; i++) {
                audioBuffer[i] = audioData.charCodeAt(i);
            }

            // 创建AudioBuffer
            const buffer = audioContext.createBuffer(1, audioBuffer.length / 2, sampleRate);
            const channelData = buffer.getChannelData(0);

            // 将PCM数据转换为浮点数
            for (let i = 0; i < audioBuffer.length; i += 2) {
                const sample = (audioBuffer[i] | (audioBuffer[i + 1] << 8)) / 32768.0;
                channelData[i / 2] = sample;
            }

            // 播放音频
            const source = audioContext.createBufferSource();
            source.buffer = buffer;
            source.connect(audioContext.destination);

            isPlaying = true;
            updateStatus('正在播放AI回答...', 'playing');
            
            // 更新播放按钮状态
            if (playButton && !playButton.classList.contains('hidden')) {
                playButton.classList.add('playing');
                playButton.textContent = '⏸️ 播放中';
            }

            source.onended = function () {
                isPlaying = false;
                updateStatus('AI回答播放完成', 'completed');
                
                // 恢复播放按钮状态
                if (playButton && !playButton.classList.contains('hidden')) {
                    playButton.classList.remove('playing');
                    playButton.textContent = '▶️ 播放录音';
                }
            };

            source.start();
            console.log('开始播放音频');

        } catch (error) {
            console.error('音频播放失败:', error);
            updateStatus(`音频播放失败: ${error.message}`, 'error');
        }
    }

    // 开始/停止录音
    function toggleRecording() {
        console.log('toggleRecording 被调用, isRecording:', isRecording, 'isPlaying:', isPlaying);

        if (isRecording) {
            // 正在录音，停止录音
            stopRecording();
        } else if (!isRecording && !isPlaying) {
            // 未录音且未播放，开始录音
            startRecording();
        } else {
            console.log('当前状态不允许录音操作');
        }
    }

    // 开始录音
    function startRecording() {
        console.log('开始录音...');

        navigator.mediaDevices.getUserMedia({audio: true})
            .then(function (stream) {
                console.log('麦克风权限获取成功');

                mediaRecorder = new MediaRecorder(stream);
                audioChunks = [];

                mediaRecorder.ondataavailable = function (event) {
                    console.log('收到音频数据块，大小:', event.data.size);
                    audioChunks.push(event.data);
                };

                mediaRecorder.onstop = function () {
                    console.log('录音停止，处理音频数据...');

                    // 注意：isRecording 已经在 stopRecording() 中设置为 false
                    // 这里只需要处理音频数据和最终状态

                    // 创建音频Blob
                    recordedAudioBlob = new Blob(audioChunks, {type: 'audio/webm'});
                    console.log('录音完成，音频大小:', recordedAudioBlob.size, '字节');

                    // 显示播放按钮
                    playButton.classList.remove('hidden');

                    // 上传音频到后端
                    uploadAudioToBackend(recordedAudioBlob);

                    // 停止音频流
                    stream.getTracks().forEach(track => track.stop());

                    console.log('录音状态已更新完成');
                };

                mediaRecorder.start();
                isRecording = true;
                voiceButton.classList.add('recording');
                playButton.classList.add('hidden'); // 隐藏播放按钮
                updateStatus('正在录音...', 'recording');
                visualizer.classList.add('active');

                console.log('录音开始');

            })
            .catch(function (error) {
                console.error('录音失败:', error);
                updateStatus(`录音失败: ${error.message}`, 'error');
            });
    }

    // 停止录音
    function stopRecording() {
        console.log('停止录音...');

        if (mediaRecorder && isRecording) {
            console.log('正在停止MediaRecorder...');

            // 立即更新UI状态，避免重复点击
            isRecording = false;
            voiceButton.classList.remove('recording');
            visualizer.classList.remove('active');
            updateStatus('正在停止录音...', 'stopping');

            // 停止录音器
            mediaRecorder.stop();
            console.log('MediaRecorder.stop() 已调用');
        } else {
            console.log('没有活动的录音器或未在录音状态');
            // 强制更新状态
            isRecording = false;
            voiceButton.classList.remove('recording');
            visualizer.classList.remove('active');
            updateStatus('录音已停止', 'completed');
        }
    }

    // 上传音频到后端
    function uploadAudioToBackend(audioBlob) {
        console.log('上传音频到后端...');
        
        const formData = new FormData();
        formData.append('audio', audioBlob, 'recording.webm');
        
        updateStatus('正在上传音频...', 'processing');
        
        fetch('/api/upload_audio', {
            method: 'POST',
            body: formData
        })
        .then(response => {
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            return response.json();
        })
        .then(data => {
            console.log('音频上传成功:', data);
            
            if (data.transcription) {
                updateStatus(`识别结果: ${data.transcription}`, 'completed');
            }
            
            if (data.ai_response) {
                updateStatus(`AI回答: ${data.ai_response}`, 'completed');
            }
            
            if (data.audio_data) {
                playAudio(data.audio_data, data.sample_rate);
            }
        })
        .catch(error => {
            console.error('音频上传失败:', error);
            updateStatus('音频上传失败: ' + error.message, 'error');
        });
    }

    // 播放录制的音频
    function playRecordedAudio() {
        console.log('播放录制的音频...');

        if (!recordedAudioBlob) {
            console.log('没有录制的音频');
            updateStatus('请先录制音频', 'error');
            return;
        }

        try {
            // 创建音频URL
            const audioUrl = URL.createObjectURL(recordedAudioBlob);
            console.log('创建音频URL:', audioUrl);

            // 创建音频元素
            const audio = new Audio(audioUrl);

            // 设置播放事件
            audio.onloadstart = function () {
                console.log('开始加载音频');
                updateStatus('正在加载音频...', 'loading');
            };

            audio.oncanplay = function () {
                console.log('音频可以播放');
                updateStatus('音频准备就绪', 'ready');
            };

            audio.onplay = function () {
                console.log('开始播放音频');
                isPlaying = true;
                playButton.classList.add('playing');
                playButton.textContent = '⏸️ 播放中';
                updateStatus('正在播放录音...', 'playing');
            };

            audio.onended = function () {
                console.log('音频播放结束');
                isPlaying = false;
                playButton.classList.remove('playing');
                playButton.textContent = '▶️ 播放录音';
                updateStatus('播放完成', 'completed');

                // 清理URL
                URL.revokeObjectURL(audioUrl);
            };

            audio.onerror = function (error) {
                console.error('音频播放错误:', error);
                isPlaying = false;
                playButton.classList.remove('playing');
                playButton.textContent = '▶️ 播放录音';
                updateStatus('播放失败', 'error');

                // 清理URL
                URL.revokeObjectURL(audioUrl);
            };

            // 开始播放
            audio.play().catch(function (error) {
                console.error('播放失败:', error);
                updateStatus('播放失败: ' + error.message, 'error');
            });

        } catch (error) {
            console.error('播放音频时发生错误:', error);
            updateStatus('播放失败: ' + error.message, 'error');
        }
    }

    // 开始对话（使用默认音频文件）
    function startConversation() {
        updateStatus('HTTP模式下不支持默认音频文件测试', 'info');
    }

    // 测试AI服务
    function testAIServices() {
        updateStatus('正在测试AI服务...', 'processing');
        
        fetch('/api/test', {
            method: 'GET'
        })
        .then(response => response.json())
        .then(data => {
            if (data.status === 'success') {
                updateStatus('AI服务测试成功', 'success');
                console.log('测试结果:', data.data);
            } else {
                updateStatus(`测试失败: ${data.message}`, 'error');
            }
        })
        .catch(error => {
            console.error('测试失败:', error);
            updateStatus('测试失败: ' + error.message, 'error');
        });
    }


    // 静音
    function toggleMute() {
        if (audioContext) {
            if (audioContext.state === 'running') {
                audioContext.suspend();
                updateStatus('已静音', 'muted');
            } else {
                audioContext.resume();
                updateStatus('已取消静音', 'unmuted');
            }
        }
    }

    // 退出对话
    function exitConversation() {
        if (isRecording) {
            stopRecording();
        }
        if (isPlaying) {
            isPlaying = false;
        }
        updateStatus('已退出对话', 'exited');
    }

    // 键盘快捷键
    document.addEventListener('keydown', function (event) {
        if (event.code === 'Space' && event.target === document.body) {
            event.preventDefault();
            // 添加状态检查，避免在播放时触发
            if (!isPlaying) {
                toggleRecording();
            }
        }
    });
</script>

</body>
</html>
